package net.zf.web;

import io.micrometer.observation.ObservationRegistry;
import net.zf.base.ApplicationContextProvider;
import net.zf.base.ZFChatClient;
import net.zf.base.ZFChatClientBuilder;
import net.zf.context.ModelContext;
import net.zf.context.ModelInfo;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.prompt.ChatOptions;
import org.springframework.ai.model.SimpleApiKey;
import org.springframework.ai.model.tool.DefaultToolCallingManager;
import org.springframework.ai.model.tool.ToolCallingManager;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.ai.template.TemplateRenderer;
import org.springframework.ai.tool.execution.DefaultToolExecutionExceptionProcessor;
import org.springframework.ai.tool.execution.ToolExecutionExceptionProcessor;
import org.springframework.ai.tool.resolution.SpringBeanToolCallbackResolver;
import org.springframework.ai.tool.resolution.ToolCallbackResolver;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.retry.support.RetryTemplate;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.DefaultResponseErrorHandler;
import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestClient;
import org.springframework.web.context.support.GenericWebApplicationContext;
import org.springframework.web.reactive.function.client.WebClient;

import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/model")
public class ModelController {

    @Autowired
    private ApplicationContextProvider applicationContextProvider;

    @Autowired
    private ChatClient chatClient;

    @GetMapping("/default")
    public String setDefaultModel(@RequestParam(value = "id", required = false)String id){

        ModelInfo modelInfo = ModelContext.getModel(id);

        MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();

        // 请求响应错误处理类
        ResponseErrorHandler responseErrorHandler = new DefaultResponseErrorHandler();


        // 构建OpenAiApi对象
        OpenAiApi openAiApi = new OpenAiApi(modelInfo.getBaseUrl(),
                new SimpleApiKey(modelInfo.getApiKey()), headers, modelInfo.getCompletionPath(), modelInfo.getEmbeddingsPath(), RestClient.builder(), WebClient.builder(),responseErrorHandler);


        // 构建OpenAIChatOptions对象
        OpenAiChatOptions openAiChatOptions = OpenAiChatOptions
                .builder()
                .model(modelInfo.getModel())
                .build();

        ToolCallbackResolver toolCallbackResolver = new SpringBeanToolCallbackResolver((GenericWebApplicationContext)applicationContextProvider.getApplicationContext(), null);
        ToolExecutionExceptionProcessor toolExecutionExceptionProcessor = new DefaultToolExecutionExceptionProcessor(false);

        DefaultToolCallingManager toolCallingManager =
                new DefaultToolCallingManager(ObservationRegistry.create(), toolCallbackResolver, toolExecutionExceptionProcessor);

        OpenAiChatModel chatModel = new OpenAiChatModel(openAiApi, openAiChatOptions, toolCallingManager, RetryTemplate.defaultInstance(), ObservationRegistry.create());

        ZFChatClient chatClient =  (ZFChatClient) applicationContextProvider.getApplicationContext().getBean(ChatClient.class);

        ZFChatClient.DefaultChatClientRequestSpec defaultChatClientRequestSpec = new ZFChatClient.DefaultChatClientRequestSpec(chatModel, (String)null, Map.of(), (String)null, Map.of(), List.of(), List.of(), List.of(), List.of(), (ChatOptions)null, List.of(), Map.of(), ObservationRegistry.create(), null, Map.of(), (TemplateRenderer)null);
        chatClient.setDefaultChatClientRequest(defaultChatClientRequestSpec);

        return "success";
    }

    @GetMapping("/chat")
    public String chat(@RequestParam String message){
        return chatClient.prompt().user(message).call().content();
    }

    @GetMapping("/chat2")
    public String chat2(@RequestParam String message){
        return  applicationContextProvider.getApplicationContext().getBean(ChatClient.class).prompt().user(message).call().content();

    }
}
